package nl.hanze.designpatterns.io;

import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

public class CryptedInputStream extends InputStream {

	private Cipher cipher;
	private SecretKeySpec secretkeyspec;
	
	private InputStream inputstream;
	
	public CryptedInputStream(InputStream inputStream, byte[] hashKey) {
		this.secretkeyspec = new SecretKeySpec(hashKey, "AES");
		this.inputstream = inputStream;
	}
	
	private void init() throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException{
		this.cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
		this.cipher.init(Cipher.ENCRYPT_MODE, this.secretkeyspec);	
	}

		
	@Override
	public int read() throws IOException {
		try {
			this.init();
			
			byte[] buffer = new byte[16];
			
			if(this.inputstream.read(buffer) < 0){
				return -1;
			}
			
			byte[] decryptedData = this.cipher.doFinal(buffer);
			
			if(decryptedData.length != 1){
				throw new IllegalStateException(String.format("Encryption to short expected length of 1", decryptedData.length));
			}
			
			return decryptedData[0];
			
			
		} catch (InvalidKeyException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchProviderException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (BadPaddingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return -1;
	}
	
	@Override
	public int available() throws IOException{
		return this.inputstream.available()/16;
	}
	
	public byte[] completeReadOut() throws IOException{
		byte[] buffer = new byte[this.available()];
		int b, i = 0;
		while((b = this.read()) > 0){
			buffer[i] = (byte) b;
			i++;
		}
		return buffer;
	}

}
